/**
 * 所有版权归 广西梧州 陈锦韬 所有
 *
 * @Title: UserDetailsServiceImpl
 * @Package com.rx.service.base
 * @Description: 用户明细实现类
 * @author: 陈锦韬
 * @date: 2020\5\20 0020
 * @version V1.0
 * @Copyright: 2020 陈锦韬  All rights reserved.
 */
package com.rx.uua.service;


import com.alibaba.fastjson.JSON;
import com.rx.core.base.RxBaseConstant;
import com.rx.core.base.RxBaseData;
import com.rx.core.base.RxResponse;
import com.rx.core.bean.LoginUserInfo;
import com.rx.core.enm.*;
import com.rx.core.iface.IUserDetailsService;
import com.rx.core.iface.InputMode;
import com.rx.core.iface.RelationQuery;
import com.rx.core.iface.RxContent;
import com.rx.core.service.RxBaseAbstractService;
import com.rx.core.service.StandardService;
import com.rx.core.util.EmptyChecker;
import com.rx.core.util.RxContentHolder;
import com.rx.core.util.RxUtil;
import com.rx.uua.enm.RELATION_TYPE;
import com.rx.uua.vo.*;
import com.rx.uua.vo.relation.DoubleUuaOrgInfo;
import com.rx.uua.vo.relation.DoubleUuaRelGroup;
import com.rx.uua.vo.relation.DoubleUuaRoleInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: Administrator
 * @Description: 用户明细实现类
 * @date: 2020\5\20 0020
 */
@Slf4j
@Component("rxUserDetailsService")
public class RxUserDetailsService extends RxBaseAbstractService implements IUserDetailsService {

    @Autowired
    StandardService standardService;

    @Autowired
    SystemService systemService;

    //@Autowired
    //TokenEndpoint tokenEndpoint;

    private List<LoginUserInfo.OrgInfo> searchOrgList(String userBid){
        try {
            DoubleUuaOrgInfo condition = (DoubleUuaOrgInfo)RxBaseData.create(DoubleUuaOrgInfo.class, UuaRelUserOrg.class,HANDLER_TYPE.DOUBLE_LIST);
            ((UuaRelUserOrg) ((RelationQuery) condition).obtainRelation()).setItemBid(userBid);
            ((UuaRelUserOrg) ((RelationQuery) condition).obtainRelation()).setRelationType(RELATION_TYPE.DEFAULT.getValue());
            ((UuaRelUserOrg) ((RelationQuery) condition).obtainRelation()).setStatus(RX_STATUS.NORMAL.getCode());
            condition.setStatus(RX_STATUS.NORMAL.getCode());
            condition.getHandlerController().onlyDefault();
            Object result = standardService.innerSearchList(condition);
            List<DoubleUuaOrgInfo> list = RxUtil.result(result);
            if (EmptyChecker.isEmpty(list)){
                return new ArrayList<>();
            }
            List<LoginUserInfo.OrgInfo> resultList = new ArrayList<>();
            for (DoubleUuaOrgInfo doubleUuaOrgInfo : list) {
                log.info(RX_LOG_MODE.DEFAULT.getFormat("{}"),"加入组织",doubleUuaOrgInfo.getOrgName());
                LoginUserInfo.OrgInfo orgInfo = new LoginUserInfo.OrgInfo();
                RxUtil.copyProperties(doubleUuaOrgInfo,orgInfo);
                resultList.add(orgInfo);
            }
            return resultList;
        } catch (IllegalAccessException | InstantiationException e) {
            log.error(RX_LOG_MODE.ERROR.getFormat("获取用户加入机构失败"));
        }
        return new ArrayList<>();
    }

    private List<LoginUserInfo.OrgInfo> searchTopOrgList(List<LoginUserInfo.OrgInfo> list){
        try {
            List<LoginUserInfo.OrgInfo> oldOrgList = list.stream()
                    .filter(e->RxBaseConstant.ORG_ROOT.equalsIgnoreCase(e.getRootCode()))
                    .distinct()
                    .collect(Collectors.toList());
            List<String> listRootCode = list.stream()
                    .filter(e->!RxBaseConstant.ORG_ROOT.equalsIgnoreCase(e.getRootCode()))
                    .map(LoginUserInfo.OrgInfo::getRootCode)
                    .distinct()
                    .collect(Collectors.toList());
            List<LoginUserInfo.OrgInfo> resultList = new ArrayList<>();
            if(EmptyChecker.notEmpty(listRootCode)){
                UuaOrgInfo condition = (UuaOrgInfo)RxBaseData.create(UuaOrgInfo.class, HANDLER_TYPE.SINGLE_LIST);
                Map<String,Object> map = new HashMap<>();
                // 去掉一切处理器
                condition.getHandlerController().onlyDefault();
                map.put("inOrgCode",listRootCode);
                condition.setCondition(map);
                condition.getHandlerController().onlyDefault();
                condition.setStatus(RX_STATUS.NORMAL.getCode());
                Object result = standardService.searchList(condition);
                List<UuaOrgInfo> listResult = RxUtil.result(result);
                if (EmptyChecker.notEmpty(listResult)){
                    for (UuaOrgInfo doubleUuaOrgInfo : listResult) {
                        LoginUserInfo.OrgInfo orgInfo = new LoginUserInfo.OrgInfo();
                        RxUtil.copyProperties(doubleUuaOrgInfo,orgInfo);
                        resultList.add(orgInfo);
                    }
                }
            }

            if(EmptyChecker.notEmpty(oldOrgList)){
                for (LoginUserInfo.OrgInfo orgInfoItem : oldOrgList) {
                    LoginUserInfo.OrgInfo orgInfo = new LoginUserInfo.OrgInfo();
                    RxUtil.copyProperties(orgInfoItem,orgInfo);
                    if (!resultList.contains(orgInfo)){
                        resultList.add(orgInfo);
                    }
                }
            }

            return resultList;
        } catch (IllegalAccessException | InstantiationException e) {
            log.error(RX_LOG_MODE.ERROR.getFormat("获取用户加入机构失败"));
        }
        return new ArrayList<>();
    }
    List<LoginUserInfo.RoleInfo> convertFromObject(Object result){
        if (result instanceof RxResponse){
            return new ArrayList<>();
        }
        List<DoubleUuaRoleInfo> list = (List<DoubleUuaRoleInfo>)result;
        if (EmptyChecker.isEmpty(list)){
            return new ArrayList<>();
        }
        
        List<LoginUserInfo.RoleInfo> resultList = new ArrayList<>();
        for (DoubleUuaRoleInfo doubleUuaRoleInfo : list) {
            log.info(RX_LOG_MODE.DEFAULT.getFormat("{}"),"拥有角色",doubleUuaRoleInfo.getRoleName());
            LoginUserInfo.RoleInfo roleInfo = new LoginUserInfo.RoleInfo();
            RxUtil.copyProperties(doubleUuaRoleInfo,roleInfo);
            resultList.add(roleInfo);
        }
        return resultList;
    }
    private DoubleUuaRelGroup setMainSecondTableConditon(DoubleUuaRoleInfo condition){
        condition.removeSecondTableField();
        condition.removeThreeTableField();
        condition.setStatus(RX_STATUS.NORMAL.getCode());

        DoubleUuaRelGroup doubleUuaRelGroup = (DoubleUuaRelGroup) ((RelationQuery) condition).obtainRelation();
        // 关联字段UuaRoleInfo.bid=UuaRelGroup.item_bid
        doubleUuaRelGroup.setReturnType(DoubleUuaRelGroup.ASS_ITEM_BID);
        // 角色-岗位
        doubleUuaRelGroup.setRelationType(RELATION_TYPE.ROLE_TO_POST.getValue());
        doubleUuaRelGroup.setStatus(RX_STATUS.NORMAL.getCode());
        return doubleUuaRelGroup;
    }
    private List<LoginUserInfo.RoleInfo> searchRoleByUserBid(String userBid,String orgBid){
        try {
            // 双表内连接查询UuaRoleInfo，UuaRelUserRole
            Map<String,Object> conditionMap = new HashMap<>();
            // 公共设置。不受机构影响。
            conditionMap.put("inOrgBid",Arrays.asList(orgBid,RxBaseConstant.ORG_DEFAULT));
            DoubleUuaRoleInfo conditionDouble = (DoubleUuaRoleInfo)RxBaseData.create(DoubleUuaRoleInfo.class, UuaRelUserRole.class,HANDLER_TYPE.DOUBLE_LIST);
            // 设置条件。
            ((UuaRelUserRole) ((RelationQuery) conditionDouble).obtainRelation()).setItemBid(userBid);
            ((UuaRelUserRole) ((RelationQuery) conditionDouble).obtainRelation()).setCondition(conditionMap);
            ((UuaRelUserRole) ((RelationQuery) conditionDouble).obtainRelation()).setRelationType(RELATION_TYPE.DEFAULT.getValue());
            ((UuaRelUserRole) ((RelationQuery) conditionDouble).obtainRelation()).setStatus(RX_STATUS.NORMAL.getCode());
            conditionDouble.setStatus(RX_STATUS.NORMAL.getCode());
            conditionDouble.removeSecondTableField();
            Object resultSingle = standardService.innerSearchList(conditionDouble);
            List<LoginUserInfo.RoleInfo> doubleList = convertFromObject(resultSingle);

            // 三表内连接查询 UuaRoleInfo，UuaRelGroup，UuaRelUserPost
            DoubleUuaRoleInfo condition = (DoubleUuaRoleInfo)RxBaseData.create(DoubleUuaRoleInfo.class, DoubleUuaRelGroup.class,UuaRelUserPost.class,HANDLER_TYPE.THREE_LIST);
            DoubleUuaRelGroup doubleUuaRelGroup = setMainSecondTableConditon(condition);

            UuaRelUserPost uuaRelUserPost = (UuaRelUserPost)((RelationQuery) doubleUuaRelGroup).obtainRelation();
            uuaRelUserPost.setItemBid(userBid);
            uuaRelUserPost.setCondition(conditionMap);
            // 关联字段UuaRoleInfo.group_bid=UuaRelGroup.group_bid
            uuaRelUserPost.setReturnType(UuaRelUserPost.ASS_GROUP_BID);
            uuaRelUserPost.setStatus(RX_STATUS.NORMAL.getCode());
            uuaRelUserPost.setRelationType(RELATION_TYPE.DEFAULT.getValue());


            Object result = standardService.threeInnerSearchList(condition);
            doubleList.addAll(convertFromObject(result));
            return doubleList;
        } catch (IllegalAccessException | InstantiationException e) {
            log.error(RX_LOG_MODE.ERROR.getFormat("获取用户角色失败"));
        }
        return new ArrayList<>();
    }
    private Map<String,Object> conditionForOrg(List<String> bidList){
        Map<String,Object> map = new HashMap<>();
        map.put("inGroupBid",bidList);
        return map;
    }
    private List<LoginUserInfo.RoleInfo> searchRoleByOrgBidList(List<String> bidList){
        try {
            if(EmptyChecker.isEmpty(bidList)){
                return new ArrayList<>();
            }
            // 双表内连接查询UuaRoleInfo，UuaRelUserRole  // 获取某岗位下的角色。
            DoubleUuaRoleInfo conditionDouble = (DoubleUuaRoleInfo)RxBaseData.create(DoubleUuaRoleInfo.class, UuaRelGroup.class,HANDLER_TYPE.DOUBLE_LIST);
            ((UuaRelGroup) ((RelationQuery) conditionDouble).obtainRelation()).setCondition(conditionForOrg(bidList));
            conditionDouble.removeSecondTableField();
            // 关联字段UuaRoleInfo.bid=UuaRelGroup.item_bid
            conditionDouble.setReturnType(UuaRelGroup.ASS_ITEM_BID);
            conditionDouble.setStatus(RX_STATUS.NORMAL.getCode());
            // 设置关联关系机构-角色
            ((UuaRelGroup) ((RelationQuery) conditionDouble).obtainRelation()).setRelationType(RELATION_TYPE.ORG_TO_ROLE.getValue());
            ((UuaRelGroup) ((RelationQuery) conditionDouble).obtainRelation()).setStatus(RX_STATUS.NORMAL.getCode());
            // 查询。
            Object resultSingle = standardService.innerSearchList(conditionDouble);
            // 转换
            List<LoginUserInfo.RoleInfo> doubleList = convertFromObject(resultSingle);

            // 三表内连接查询 UuaRoleInfo，UuaRelGroup，UuaRelGroup 获取机构下的岗位。然后这些岗位有哪些角色。
            DoubleUuaRoleInfo condition = (DoubleUuaRoleInfo)RxBaseData.create(DoubleUuaRoleInfo.class, DoubleUuaRelGroup.class,UuaRelGroup.class,HANDLER_TYPE.THREE_LIST);
            DoubleUuaRelGroup doubleUuaRelGroup = setMainSecondTableConditon(condition);

            UuaRelGroup uuaRelGroup = (UuaRelGroup)((RelationQuery) doubleUuaRelGroup).obtainRelation();
            // 关联字段：UuaRelGroup.group_bid=UuaRelGroup.item_bid
            uuaRelGroup.setReturnType(UuaRelGroup.ASS_ITEM_BID);
            // 设置2表UuaRoleInfo，3表uuaRelGroup表关联关系机构-岗位。
            uuaRelGroup.setRelationType(RELATION_TYPE.ORG_TO_POST.getValue());
            uuaRelGroup.setCondition(conditionForOrg(bidList));
            uuaRelGroup.setStatus(RX_STATUS.NORMAL.getCode());

            Object result = standardService.threeInnerSearchList(condition);
            doubleList.addAll(convertFromObject(result));
            return doubleList;
        } catch (IllegalAccessException | InstantiationException e) {
            log.error(RX_LOG_MODE.ERROR.getFormat("获取用户角色失败"));
        }
        return new ArrayList<>();
    }

    private List<LoginUserInfo.RoleInfo> dealRoleList(List<LoginUserInfo.RoleInfo> roleInfos,List<LoginUserInfo.RoleInfo> roleInfoList){
        if (EmptyChecker.isEmpty(roleInfos) && EmptyChecker.isEmpty(roleInfoList)){
            return roleInfos;
        }

        roleInfos.addAll(roleInfoList);
        // 去重
        roleInfos = roleInfos.stream().distinct().collect(Collectors.toList());

        List<String> hasConflictBidList = roleInfos.stream()
                .filter(e -> RX_CONFLICT_FLG.HAVE.getCode().equalsIgnoreCase(e.getConflict()))
                .map(LoginUserInfo.RoleInfo::getBid).collect(Collectors.toList());

        final List<UuaRelGroup> conflictRoleList = systemService.getConflictRoleList(hasConflictBidList,RX_STATUS.NORMAL.getCode());

        if (EmptyChecker.isEmpty(conflictRoleList)){
            return roleInfos;
        }

        Set<String> roleSet = new HashSet<>();
        for (UuaRelGroup uuaRelGroup : conflictRoleList) {
            if (hasConflictBidList.contains(uuaRelGroup.getItemBid()) && hasConflictBidList.contains(uuaRelGroup.getGroupBid())){
                roleSet.add(uuaRelGroup.getItemBid());
                roleSet.add(uuaRelGroup.getGroupBid());
            }
        }
        if (EmptyChecker.isEmpty(roleSet)){
            return roleInfos;
        }

        Iterator<LoginUserInfo.RoleInfo> iterator = roleInfos.iterator();
        while (iterator.hasNext()){
            if (roleSet.contains(iterator.next().getBid())){
                iterator.remove();
            }
        }

        return roleInfos;
    }

    private List<String> getBidList(List<LoginUserInfo.OrgInfo> orgInfos,List<LoginUserInfo.OrgInfo> topOrgList,String bid){
        if(EmptyChecker.isEmpty(bid)||EmptyChecker.isEmpty(topOrgList)){
           return new ArrayList<>();
        }
        LoginUserInfo.OrgInfo current = null;

        for (LoginUserInfo.OrgInfo orgInfo : topOrgList) {
            if(orgInfo.getBid().equalsIgnoreCase(bid)){
                current = orgInfo;
                break;
            }
        }

        if(EmptyChecker.isEmpty(current)){
            return new ArrayList<>();
        }
        List<String> resultList = new ArrayList<>();
        for (LoginUserInfo.OrgInfo orgInfo : orgInfos) {
            if(orgInfo.getRootCode().equalsIgnoreCase(current.getOrgCode())||
            orgInfo.getOrgCode().equalsIgnoreCase(current.getOrgCode())){
                resultList.add(orgInfo.getBid());
            }
        }
       return resultList;
    }

    public List<LoginUserInfo.RoleInfo> getRoleList(String orgBid){
        if(EmptyChecker.isEmpty(orgBid)){
            return new ArrayList<>();
        }
        List<LoginUserInfo.RoleInfo> roleInfos = searchRoleByUserBid(RxContentHolder.getUserInfo().getBid(),orgBid);
        // 加入某个机构，自动获取角色。无需配置。
        List<String> bidList = getBidList(RxContentHolder.getOrgInfo(),RxContentHolder.getTopOrgInfo(),orgBid);

        List<LoginUserInfo.RoleInfo> roleInfoList = searchRoleByOrgBidList(bidList);

        return dealRoleList(roleInfos,roleInfoList);
    }
    private UserDetails loadUser(String conditionString, String conditionName,String orgBid,InputMode inputMode){
        RxUtil.CheckUtil.check(conditionString, RESULT_CODE.EMPTY,conditionName);
        try {
            RxBaseData condition = RxBaseData.create(UuaUserInfo.class, HANDLER_TYPE.SINGLE_LIST);
            UuaUserInfo plfUserInfo= (UuaUserInfo) condition;
            inputMode.handle(plfUserInfo);

            Object object = standardService.searchList(condition);
            RxUtil.CheckUtil.checkResult(object,RESULT_CODE.LOGIN_ERR);
            // TODO: 查询出角色、权限。

            UuaUserInfo result = (UuaUserInfo)RxUtil.ListUtil.onlyOne((List<UuaUserInfo>)object,conditionName+"绑定的用户不唯一,请用另一种方式登录");
            LoginUserInfo loginUserInfo = LoginUserInfo.create(result);

            List<LoginUserInfo.OrgInfo> orgInfos = searchOrgList(result.getBid());

            List<LoginUserInfo.OrgInfo> topOrgList = searchTopOrgList(orgInfos);
            if(EmptyChecker.isEmpty(orgBid) && EmptyChecker.notEmpty(topOrgList)){
                LoginUserInfo.OrgInfo current = (LoginUserInfo.OrgInfo)RxUtil.ListUtil.getFirst(topOrgList);
                orgBid = current.getBid();
            }
            List<String> bidList = getBidList(orgInfos,topOrgList,orgBid);

            List<LoginUserInfo.RoleInfo> roleInfos = searchRoleByUserBid(result.getBid(),orgBid);
            // 加入某个机构，自动获取角色。无需配置。
            List<LoginUserInfo.RoleInfo> roleInfoList = searchRoleByOrgBidList(bidList);

            if(!RX_USER_TYPE.SYS.getCode().equalsIgnoreCase(result.getUserType())){
                loginUserInfo.setTopOrgList(topOrgList);
                for (LoginUserInfo.OrgInfo orgInfo : topOrgList) {
                    if(orgBid.equalsIgnoreCase(orgInfo.getBid())){
                        LoginUserInfo.OrgInfo current = new LoginUserInfo.OrgInfo();
                        RxUtil.copyProperties(orgInfo,current);
                        loginUserInfo.setCurrentOrg(current);
                    }
                }
            }

            loginUserInfo.setOrgList(orgInfos);
            loginUserInfo.setRoleList(dealRoleList(roleInfos,roleInfoList));
            return   User.withUsername(JSON.toJSONString(loginUserInfo))
                    .password(result.getPassword())
                    .accountExpired(false).authorities("all").build();
        } catch (Exception e) {
            log.error(RX_LOG_MODE.ERROR.getFormat(),"创建失败");
        }
        return null;
    }

    public UserDetails loadUserByUsername(String username,String orgBid) throws UsernameNotFoundException {
        return loadUser(username,"用户名",orgBid,e->((UuaUserInfo)e).setUserName(username));
    }
    private UserDetails loadUserByEmail(String email,String orgBid) throws UsernameNotFoundException {
        return loadUser(email,"邮箱地址",orgBid,e->((UuaUserInfo)e).setEmail(email));
    }
    private UserDetails loadUserByPhone(String phone,String orgBid) throws UsernameNotFoundException {
        return loadUser(phone,"手机号",orgBid,e->((UuaUserInfo)e).setEmail(phone));
    }

    @Override
    public UserDetails loadUserByLoginClass(String username, String loginClass) throws UsernameNotFoundException {
        // 登录的机构
        String orgBid = null;
        if(EmptyChecker.notEmpty(username)){
            String[] splitString = username.split(RxBaseConstant.SPLIT_STRING);
            username = splitString[0];
            if(splitString.length > 1){
                orgBid = splitString[1];
            }
        }
        if(LOGIN_CLASS.EMAIL.getCode().equalsIgnoreCase(loginClass)){
            return loadUserByEmail(username,orgBid);
        }else if(LOGIN_CLASS.PHONE.getCode().equalsIgnoreCase(loginClass)){
            return loadUserByPhone(username,orgBid);
        }else if(LOGIN_CLASS.OTHER.getCode().equalsIgnoreCase(loginClass)){
            return null;
        }else {
            return loadUserByUsername(username,orgBid);
        }

    }

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        String orgBid = null;
        String username = null;
        if(EmptyChecker.notEmpty(s)){
            String[] splitString = s.split(RxBaseConstant.SPLIT_STRING);
            username = splitString[0];
            if(splitString.length > 1){
                orgBid = splitString[1];
            }
        }
        final String userName = username;
        return loadUser(username,"用户名",orgBid,e->((UuaUserInfo)e).setUserName(userName));
    }
}
